package com.lzh.dlykserver.config;

import com.lzh.dlykserver.config.filter.TokenVerifyFilter;
import com.lzh.dlykserver.config.handler.MyAccessDeniedHandler;
import com.lzh.dlykserver.config.handler.MyAuthenticationFailureHandler;
import com.lzh.dlykserver.config.handler.MyAuthenticationSuccessHandler;
import com.lzh.dlykserver.config.handler.MyLogoutSuccessHandler;
import com.lzh.dlykserver.constant.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;
import java.util.Collections;


@EnableGlobalMethodSecurity(prePostEnabled = true)     //开启方法级别的权限检查
@Configuration
public class SecurityConfig {

    private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
    @Resource
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Resource
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    @Resource
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    @Resource
    private TokenVerifyFilter tokenVerifyFilter;

    @Resource
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, CorsConfigurationSource corsConfigurationSource) throws Exception {
        return httpSecurity
                .formLogin((formLogin) -> {
                    formLogin.loginProcessingUrl(Constants.LOGIN_URI)  // 登录请求的url
                            .usernameParameter("loginAct")
                            .passwordParameter("loginPwd")
                            .successHandler(myAuthenticationSuccessHandler)
                            .failureHandler(myAuthenticationFailureHandler);
                })
                .authorizeHttpRequests((authorize) -> {
                    authorize.mvcMatchers("/api/login")
                            .permitAll()
                            .anyRequest()
                            .authenticated(); //任何请求都得登录后才可以访问
                })
                //禁用跨站请求伪造
                .csrf(AbstractHttpConfigurer::disable)
                //支持跨域请求
                .cors((cors) -> {
                    cors.configurationSource(corsConfigurationSource);
                })

                .sessionManagement((session) -> {
                    //session创建策略
                    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS); //无session状态
                })

                //添加自定义filter
                .addFilterBefore(tokenVerifyFilter, LogoutFilter.class)

                //退出登录
                .logout((logout) -> {
                    logout.logoutUrl("/api/logout")     //退出提交到该地址，无需写controller，框架处理
                            .logoutSuccessHandler(myLogoutSuccessHandler);
                })

                //无权限的处理
                .exceptionHandling((exception) -> {
                    exception.accessDeniedHandler(myAccessDeniedHandler);
                })

                .build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Collections.singletonList("*")); //允许任何来源，http://localhost:8081
        configuration.setAllowedMethods(Collections.singletonList("*")); //允许任何请求方法，post、get、put、delete
        configuration.setAllowedHeaders(Collections.singletonList("*")); //允许任何的请求头

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }


}
